
public class CODECInstrucao {

	private static int operacaoTam = 5; //bits
	private static int operador1Tam = 4; //bits
	private static int operador2Tam = 4; //bits
	
	// Lista de operacoes/instrucoes
	public static final String [] instrucoes =
	{
		"ADD", "SUB", "MOV", "CMP",	// aritmeticas e comparacao
		"AND", "OR", "XOR", "NOT",	// logicas
		"CLR", "NEG", "SHL", "SHR", // instrucao de um operando
		"BRZ", "BRN", "BRE", "BRL", "BRG", "BRC", "JMP",	// salto condicional
		"HALT"						// halt!
	};
	
	// Lista de operandos fonte
	public static final String [] operando1 =
	{
		"",
		"imediato",
		"R0", "R1", "R2", "R3", "R4",
		"(R0)", "(R1", "(R2)", "(R3)", "(R4)"
	};

	// Lista de operandos destino
	public static final String [] operando2 =
	{
		"", "",
		"R0", "R1", "R2", "R3", "R4",
		"(R0)", "(R1", "(R2)", "(R3)", "(R4)"
	};


	public static int codificar(String operacao, String op1, String op2)
	{
		String codigo = "";
		int i;
		boolean achou;
		
		for (achou = false, i = 0; i < instrucoes.length && !achou; i++)
		{
			if (operacao.equalsIgnoreCase(instrucoes[i]))
			{
				codigo += toBin(i, operacaoTam);
				achou = true;
			}
		}
		if (!achou) codigo += "00000";

		for (achou = false, i = 0; i < operando1.length && !achou; i++)
		{
			if (op1.equalsIgnoreCase(operando1[i]))
			{
				codigo += toBin(i, operador1Tam);
				achou = true;
			}
		}
		if (!achou) codigo += "0000";
		
		for (achou = false, i = 0; i < operando2.length && !achou; i++)
		{
			if (op2.equalsIgnoreCase(operando2[i]))
			{
				codigo += toBin(i, operador2Tam);
				achou = true;
			}
		}
		if (!achou) codigo += "0000";
/*
		if(operacao.equals("ADD")) codigo +=  toBin(0, operacaoTam);
		else if(operacao.equals("SUB")) codigo +=  toBin(1, operacaoTam);
		else if(operacao.equals("MOV")) codigo +=  toBin(2, operacaoTam);
		else if(operacao.equals("CMP")) codigo +=  toBin(3, operacaoTam);
		else if(operacao.equals("AND")) codigo +=  toBin(4, operacaoTam);
		else if(operacao.equals("OR")) codigo +=  toBin(5, operacaoTam);
		else if(operacao.equals("XOR")) codigo +=  toBin(6, operacaoTam);
		else if(operacao.equals("NOT")) codigo +=  toBin(7, operacaoTam);
		else if(operacao.equals("CLR")) codigo +=  toBin(8, operacaoTam);
		else if(operacao.equals("NEG")) codigo +=  toBin(9, operacaoTam);
		else if(operacao.equals("SHL")) codigo +=  toBin(10, operacaoTam);
		else if(operacao.equals("SHR")) codigo +=  toBin(11, operacaoTam);
		else if(operacao.equals("BRZ")) codigo +=  toBin(12, operacaoTam);
		else if(operacao.equals("BRN")) codigo +=  toBin(13, operacaoTam);
		else if(operacao.equals("BRE")) codigo +=  toBin(14, operacaoTam);
		else if(operacao.equals("BRL")) codigo +=  toBin(15, operacaoTam);
		else if(operacao.equals("BRG")) codigo +=  toBin(16, operacaoTam);
		else if(operacao.equals("BRC")) codigo +=  toBin(17, operacaoTam);
		else if(operacao.equals("JMP")) codigo +=  toBin(18, operacaoTam);
		else if(operacao.equals("HALT")) codigo +=  toBin(19, operacaoTam);

		if(op1.equals("imediato")) codigo +=  toBin(1, operador1Tam);
		else if(op1.equals("R0")) codigo +=  toBin(2, operador1Tam);
		else if(op1.equals("R1")) codigo +=  toBin(3, operador1Tam);
		else if(op1.equals("R2")) codigo +=  toBin(4, operador1Tam);
		else if(op1.equals("R3")) codigo +=  toBin(5, operador1Tam);
		else if(op1.equals("R4")) codigo +=  toBin(6, operador1Tam);
		else if(op1.equals("(R0)")) codigo +=  toBin(7, operador1Tam);
		else if(op1.equals("(R1)")) codigo +=  toBin(8, operador1Tam);
		else if(op1.equals("(R2)")) codigo +=  toBin(9, operador1Tam);
		else if(op1.equals("(R3)")) codigo +=  toBin(10, operador1Tam);
		else if(op1.equals("(R4)")) codigo +=  toBin(11, operador1Tam);
		else codigo += "0000";

		if(op2.equals("R0")) codigo +=  toBin(2, operador2Tam);
		else if(op2.equals("R1")) codigo +=  toBin(3, operador2Tam);
		else if(op2.equals("R2")) codigo +=  toBin(4, operador2Tam);
		else if(op2.equals("R3")) codigo +=  toBin(5, operador2Tam);
		else if(op2.equals("R4")) codigo +=  toBin(6, operador2Tam);
		else if(op2.equals("(R0)")) codigo +=  toBin(7, operador2Tam);
		else if(op2.equals("(R1)")) codigo +=  toBin(8, operador2Tam);
		else if(op2.equals("(R2)")) codigo +=  toBin(9, operador2Tam);
		else if(op2.equals("(R3)")) codigo +=  toBin(10, operador2Tam);
		else if(op2.equals("(R4)")) codigo +=  toBin(11, operador2Tam);
		else codigo += "0000";
*/
		return toInt(codigo, operacaoTam + operador1Tam + operador2Tam);
	}

	public static String [] decodificar(int codigo)
	{
		String bin = toBin(codigo, operacaoTam + operador1Tam + operador2Tam);

		String operacao = bin.substring(0, operacaoTam);
		String operador1 = bin.substring(operacaoTam, operacaoTam + operador1Tam);
		String operador2 = bin.substring(operacaoTam + operador1Tam, operacaoTam + operador1Tam + operador2Tam);

		String dec[] = new String[3];
		
		int i;
		boolean achou;
		
		for (achou = false, i = 0; i < instrucoes.length && !achou; i++)
		{
			if (operacao.equalsIgnoreCase(toBin(i, operacaoTam)))
			{
				dec[0] = instrucoes[i];
				achou = true;
			}
		}

		for (achou = false, i = 0; i < operando1.length && !achou; i++)
		{
			if (operador1.equalsIgnoreCase(toBin(i, operador1Tam)))
			{
				dec[0] = operando1[i];
				achou = true;
			}
		}
		
		for (achou = false, i = 0; i < operando2.length && !achou; i++)
		{
			if (operador2.equalsIgnoreCase(toBin(i, operador2Tam)))
			{
				dec[0] = operando2[i];
				achou = true;
			}
		}
/*
		int r = 0;
		if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "ADD";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "SUB";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "MOV";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "CMP";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "AND";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "OR";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "XOR";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "NOT";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "CLR";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "NEG";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "SHL";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "SHR";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRZ";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRN";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRE";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRL";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRG";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "BRC";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "JMP";
		else if(operacao.equals(toBin(r++, operacaoTam))) dec[0] = "HALT";

		r = 0;
		if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "imediato";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "R0";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "R1";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "R2";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "R3";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "R4";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "(R0)";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "(R1)";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "(R2)";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "(R3)";
		else if(operador1.equals(toBin(r++, operador1Tam))) dec[1] = "(R4)";

		r = 0;
		if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "R0";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "R1";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "R2";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "R3";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "R4";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "(R0)";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "(R2)";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "(R2)";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "(R3)";
		else if(operador2.equals(toBin(r++, operador2Tam))) dec[2] = "(R4)";
*/
		return dec;
	}

	private static int toInt(String bin, int tam)
	{
		int codigo = 0;
		for(int i=tam-1 ; i>=0 ; i--)
			if(Integer.parseInt(bin.substring(i, i+1)) == 1)
				codigo += Math.pow(2, tam-1-i);
		return codigo;
	}

	private static String toBin(int n, int tam)
	{
		String entrada = Integer.toBinaryString(n);
		String zeros = "";
		for (int i = 0; i < tam - entrada.length(); i++) {
			zeros += "0";
		}

		String saida = zeros + entrada;
		return saida;
	}

	public static int decodificarOperacao(String operacao)
	{
		int i;			
		for (i = 0; i < instrucoes.length; i++)
		{
			if (operacao.equalsIgnoreCase(toBin(i, operacaoTam))) return i;
		}
		/*
		if(operacao.equals("ADD")) return 0;
		else if(operacao.equals("SUB")) return 1;
		else if(operacao.equals("MOV")) return 2;
		else if(operacao.equals("CMP")) return 3;
		else if(operacao.equals("AND")) return 4;
		else if(operacao.equals("OR"))  return 5;
		else if(operacao.equals("NOT")) return 6;
		else if(operacao.equals("CLR")) return 7;
		else if(operacao.equals("NEG")) return 8;
		else if(operacao.equals("SHL")) return 9;
		else if(operacao.equals("SHR")) return 10;
		else if(operacao.equals("BRZ")) return 11;
		else if(operacao.equals("BRN")) return 12;
		else if(operacao.equals("BRE")) return 13;
		else if(operacao.equals("BRL")) return 14;
		else if(operacao.equals("BRG")) return 15;
		else if(operacao.equals("BRC")) return 16;
		else if(operacao.equals("JMP")) return 17;
		else if(operacao.equals("HALT")) return 18;
		*/
		return -1;
	}
}
